package com.lakeworks.framework.web.service;

import com.lakeworks.common.core.domain.entity.RoleDTO;
import com.lakeworks.common.core.domain.entity.SysRole;
import com.lakeworks.common.core.domain.entity.SysUser;
import com.lakeworks.common.core.domain.entity.UserDTO;
import com.lakeworks.common.core.domain.model.LoginUser;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.time.Instant;

import static com.lakeworks.common.constant.Constants.*;
import static com.lakeworks.common.utils.bean.DeepCopyUtil.transform;
import static com.lakeworks.common.utils.bean.DeepCopyUtil.transformList;
import static io.jsonwebtoken.Header.JWT_TYPE;
import static io.jsonwebtoken.Header.TYPE;
import static io.jsonwebtoken.SignatureAlgorithm.HS512;
import static io.jsonwebtoken.security.Keys.hmacShaKeyFor;
import static java.time.temporal.ChronoUnit.MINUTES;
import static java.util.Date.from;
import static java.util.stream.Collectors.toSet;
import static org.apache.commons.lang3.StringUtils.isNotBlank;

@Slf4j
@Component
public class TokenService {

    @Value("${token.secret}")
    private String secret;

    @Value("${token.expireTime}")
    private int expireTime;

    public LoginUser getLoginUser(HttpServletRequest request) {
        String token = getToken(request);
        if (isNotBlank(token)) {
            log.info("get token from request：[{}]", token);
            try {
                SysUser sysUser = transform(parseToken(token).get(JWT_USER), SysUser.class);
                return new LoginUser(sysUser.getUserId(), sysUser, sysUser.getRoles().stream().map(SysRole::getRoleKey).collect(toSet()));
            } catch (Exception e) {
                log.error("loginUser获取失败，message：{}", e.getMessage());
            }
        }
        return null;
    }

    public String createToken(SysUser user, String openId) {
        return jwtBuilder(Jwts.builder()
                .setSubject(openId)
                .claim(JWT_USER, convert(user)));
    }

    private String createToken(Claims claims) {
        return jwtBuilder(Jwts.builder()
                .setClaims(claims));
    }

    private String jwtBuilder(JwtBuilder builder) {
        Instant now = Instant.now();
        String token = builder.setHeaderParam(TYPE, JWT_TYPE)
                .setIssuedAt(from(now))
                .setExpiration(from(now.plus(expireTime, MINUTES)))
                .signWith(hmacShaKeyFor(secret.getBytes()), HS512)
                .compact();
        log.info("生成token：[{}]", token);
        return token;
    }

    private Claims parseToken(String token) {
        return Jwts.parserBuilder()
                .setSigningKey(hmacShaKeyFor(secret.getBytes()))
                .build()
                .parseClaimsJws(token)
                .getBody();
    }

    public String getToken(HttpServletRequest request) {
        String token = request.getHeader(JWT_AUTHORIZATION);
        if (isNotBlank(token) && token.startsWith(TOKEN_PREFIX)) {
            token = token.replace(TOKEN_PREFIX, "");
        }
        return token;
    }

    public String renewToken(HttpServletRequest request) {
        return createToken(parseToken(getToken(request)));
    }

    private UserDTO convert(SysUser user) {
        return transform(user, UserDTO.class)
                .setRoles(transformList(user.getRoles(), RoleDTO.class));
    }
}
